package worker

import (
	"../common"
	"os/exec"
	"time"
	"math/rand"
)

//任务执行器
type Executor struct {
}

var (
	G_executor *Executor
)

//真正的执行一个任务,因为我们有很多任务,所以每一个任务对应一个协程
func (executor *Executor) ExecuteJob(info *common.JobExecuteInfo) {
	go func() {
		var (
			cmd     *exec.Cmd
			err     error
			output  []byte
			result  *common.JobExecuteResult
			jobLock *JobLock
		)

		//任务执行完成后,把执行的结果返回给Scheduler,Scheduler会从executingRable中删除记录
		result = &common.JobExecuteResult{
			ExecuteInfo: info,
			Output:      make([]byte, 0),
		}

		//为了防止多个机器同时对相同的任务做执行,则需要分布式锁
		//分布式锁：保证了,一个任务在N个机器中被执行一次
		jobLock = G_jobMgr.CreateJobLock(info.Job.Name)

		//记录任务开始时间
		result.StartTime = time.Now()

		//上锁
		//随机睡眠(0-1s)
		time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
		err = jobLock.TryLock()
		defer jobLock.Unlock()

		if err != nil { //上锁失败
			result.Err = err
			result.EndTime = time.Now()
		} else {
			//上锁成功
			//重置任务启动时间
			result.StartTime = time.Now()
			//执行shell命令
			cmd = exec.CommandContext(info.CancelCtx, "/bin/bash", "-c", info.Job.Command)

			//执行并捕获输出
			output, err = cmd.CombinedOutput()

			//记录任务结束时间
			result.EndTime = time.Now()
			result.Output = output
			result.Err = err
		}
		//任务执行完成后,把执行结果返回给Scheduler,Scheduler会从executingTable中删除任务执行记录
		G_scheduler.PushJobResult(result)
	}()
}

//初始化执行器,返回当前类的全局对象
func InitExecutor() (err error) {
	G_executor = &Executor{}
	return
}
